	title	NAME.LDD device driver for S3/S3a/S3c/S3../HC
	subttl	Copyright PSION PLC November 1995
	name	NAME

;	VERSION   DATE     DESCRIPTION
;	------- -------- ---------------
;	  1.0   12/01/95 Template Asic4/5 LDD

;	Written by Jason Robinson January 1995

        BUILDSB	                equ	1
        Asic4Type               =0
        Asic5Type               =0
        NeedTheInterrupt        =0
        NeedClocking            =0
        StartChannelInOpen      =0

        include ..\inc\epoc.inc
        include ..\inc\epocser.inc
        include ..\inc\epoclib.inc
        include ..\inc\epocsibo.inc
        include ..\srcs\ossibo.inc
	include ..\srcs\ospack.inc
	
        WeSupportS3Only         equ     Lcd240X80
        WeSupportS3aOnly        equ     Lcd480X160
        WeSupportS3cOnly        equ     Lcd240X100
        WeSupportHCOnly         equ     Lcd160X80
if      Consumer
        NumberOfChannels        equ     1
  if    Asic9
        TheMachineWeSupport     equ     WeSupportS3aOnly
  else      
        TheMachineWeSupport     equ     WeSupportS3Only
  endif
else
        NumberOfChannels        equ     3
  if    Asic9
        TheMachineWeSupport     equ     WeSupportS3cOnly
  else      
        TheMachineWeSupport     equ     WeSupportHCOnly
  endif
endif
	A4PERIPH_MASK           equ	0f0h
        TheInfoByteThatWeWant   equ     1

TmpltEnt struc
        TmpltEntOpen            db      ?       ; Channel open flag
        TmpltChannelStarted     db      ?       ; Channel should be running
        TmpltHwChannel          dw      ?       ; The harware we want
        TmpltStructPtr          dw      ?       ; Ptr to CB in Apps DS
        TmpltTckHandle          dw      ?       ; Tick Handle
        TmpltChannelRunning     db      ?       ; Can channel really run
        TmpltInterruptMask      db      ?       ; InterruptMask
        TmpltChannel            db      ?       ; Channel
if      NeedTheInterrupt
        TmpltInterruptNumber    db      ?       ; Interrupt Number
        TmpltInterruptVector    dw      ?       ; Were to Jump To
if      Asic5Type and NeedClocking
        TmpltA5Clocking         db      ?       ; Asic5 baud rate clocking 
        TmpltSpare              db      ?
endif
else
        TmpltSpare              db      ?
endif
        
TmpltEnt ends

TmpltStruct struc
        Tmpltblk		ChanEnt <>      ; I/O control block
        TmpltEntPtr             dw      ?       ; Ptr to our CS CB
TmpltStruct ends

	dgroup group stack
	assume ds:dgroup,es:dgroup,ss:dgroup

	CodeSeg
	
	ProcBegin@ TmpltLDD
;	===================

	dw	LDDSignature
	db	'HSB',0,0,0,0,0
	dw	(TableEnd-TableStart)/2
TableStart:
	dw	TmpltInstall
	dw	TmpltRemove
	dw	TmpltHold
	dw	TmpltResume
        dw      TmpltReset
        dw      TmpltUnits
        dw      TmpltOpen
        dw      TmpltStrategy
MonitorVector:
        dw      MonitorInt
TableEnd:

if Consumer
  if Asic9
        SetupTable      db      mask A9MSlave,SelectChannel5
                        db      (mask A9MClockEnable5 shr 8),HwIrq2Revector
    if      NeedTheInterrupt
                        dw      offset Interrupt0
    endif
                        
  else
        SetupTable      db      mask Asic2Int,SelectChannel7
                        db      (mask ClockEnable7 shr 8),HwIrq4Revector
    if      NeedTheInterrupt
                        dw      offset Interrupt0
    endif
  endif
else
  if Asic9
        SetupTable      db      mask A9MExpIntA,SelectChannel3
                        db      (mask A9MClockEnable3 shr 8),HwIrq4Revector
    if      NeedTheInterrupt
                        dw      offset Interrupt0
    endif
                        db      mask A9MExpIntB,SelectChannel4
                        db      (mask A9MClockEnable4 shr 8),HwIrq5Revector
    if      NeedTheInterrupt
                        dw      offset Interrupt1
    endif
                        db      mask A9MSlave,SelectChannel5
                        db      (mask A9MClockEnable5 shr 8),HwIrq2Revector
    if      NeedTheInterrupt
                        dw      offset Interrupt2
    endif
  else
        SetupTable      db      mask ExpIntLeftA,ExpChannelLeftA
                        db      (mask ClockEnable6 shr 8),HwIrq3Revector
    if      NeedTheInterrupt
                        dw      offset Interrupt0
    endif
                        db      mask ExpIntRightB,ExpChannelRightB
                        db      (mask ClockEnable5 shr 8),HwIrq2Revector
    if      NeedTheInterrupt
                        dw      offset Interrupt1
    endif
                        db      mask Asic2Int,SelectChannel7
                        db      (mask ClockEnable7 shr 8),HwIrq4Revector
    if      NeedTheInterrupt
                        dw      offset Interrupt2
    endif
  endif
endif
	CsHeldFlag	db	0			; Ldd under a hold?
        MachineType     db      0
if      Consumer
        Channel0        TmpltEnt <>
else
        Channel0        TmpltEnt <>
        Channel1        TmpltEnt <>
        Channel2        TmpltEnt <>
endif
			
	ProcEnd noret

	ProcBegin@ TmpltInstall,far
;	===========================

;	Install the driver
;	Exit with carry clear for okay

	GenLcdType                                      ; Do we only run on
        mov     MachineType,al                          ; particular machines?
        cmp     al,TheMachineWeSupport
        jne     CannotInstallOnThisMachine

        pushf
        cli
        push    ds
        mov     ax, cs
        mov     ds, ax     
	mov	CsHeldFlag, 0				; Initialise all
        mov     cx, NumberOfChannels                    ; the variables
        mov     di, offset Channel0
        mov     si, offset SetupTable
ResetAllChannelsLoop:
        mov     [di].TmpltEntOpen, 0
        lodsb        
        mov     [di].TmpltInterruptMask, al
        lodsb        
        mov     [di].TmpltChannel, al
        lodsb        
if      NeedClocking
        mov     [di].TmpltA5Clocking, al
endif
        lodsb        
if      NeedTheInterrupt
        mov     [di].TmpltInterruptNumber, al
        lodsw
        mov     [di].TmpltInterruptVector, ax
endif

        add     di,size TmpltEnt
        loop    ResetAllChannelsLoop
        pop     ds
        popf
FinishedOkay:						
	clc						
	ret
CannotInstallOnThisMachine:
        mov     ax,NotSupportedErr
        stc
        ret						
	ProcEnd noret

	ProcBegin@ TmpltRemove,far
;	==========================

;	Remove the driver
;	Exit with carry clear for okay
;	Exit with carry set if channel still open

        mov     cx,NumberOfChannels
        mov     di,offset Channel0
        xor     ax,ax
CheckAllChannelsClosedLoop:
        cmp     cs:[di].TmpltEntOpen,al
        jne     WeHaveAnOpenChannelSoFail
        add     di,size TmpltEnt
        loop    CheckAllChannelsClosedLoop
        jmp     FinishedOkay
WeHaveAnOpenChannelSoFail:
	mov 	ax,InUseErr
	stc
	ret
	ProcEnd noret

	ProcBegin@ TmpltUnits,far
;	=========================

;	Return the Number of channels that can be opened in AX

	mov	ax,NumberOfChannels     		; We have ? channels
	ret
	ProcEnd noret

	ProcBegin@ TmpltReset,far
;	=========================

;	Reset the open channel

        mov     di,cx
	cmp	cs:[di].TmpltEntOpen,0			; Somethings gone
	je	NotOpenToReset				; wrong with the
        mov     ah,DevHoldPowerDown                     ; application that 
	call	StopTheChannel				; opened us.
        call    FreeHardware                            ; Stop interupts and
	mov	cs:[di].TmpltEntOpen,0			; free the channel 
NotOpenToReset:						
	ret						
	ProcEnd noret

	ProcBegin@ TmpltHold,far
;	========================
	
;	Hold the channels
;       Hold reason in AH

	mov	cx,1
	xchg	cl,CsHeldFlag				; Stop any interrupts
	cmp	cl,0					; Mark channel as
	jne	AlreadyHeld				; under a normal hold
DoHold:
        mov     cx,NumberOfChannels
        mov     di,offset Channel0
HoldAllTheChannelsLoop:
        cmp     cs:[di].TmpltEntOpen,0
        je      DontHoldBecauseNotOpen
        cmp     cs:[di].TmpltChannelStarted,0
        je      DontHoldBecauseNotOpen
        push    ax
        push    cx
	call	StopTheChannel
        pop     cx
        pop     ax
DontHoldBecauseNotOpen:
        add     di,size TmpltEnt
        loop    HoldAllTheChannelsLoop
AlreadyHeld:
	ret
	ProcEnd noret

	ProcBegin@ TmpltResume,far
;	==========================

;	Resume the channel

	xor	cx,cx					; Be warned during an
	xchg	cl,CsHeldFlag				; on/off the power to
	cmp	cl,0					; ASIC4 is not restored
	je	AlreadyResumed				; until after this
	GenDataSegment		 			; A resume is pointless
	HwGetSsdData					; if there is still no
	mov	bx,ax					; power to the port
	cmp	es:[bx].SsdDoorStatus,DoorOpen		; Leave the resume
	je	DoorsAreOpen				; to the tick
DoResume:
        mov     cx,NumberOfChannels
        mov     di,offset Channel0                      ; Right hardware?
ResumeAllTheChannelsLoop:                               ; Else restart
        cmp     cs:[di].TmpltEntOpen,0                  ; interrupts    
        je      DontResumeBecauseNotOpen
        cmp     cs:[di].TmpltChannelStarted,0
        je      DontResumeBecauseNotOpen
        push    cx
	call	StartTheChannel
        pop     cx
DontResumeBecauseNotOpen:
        add     di,size TmpltEnt
        loop    ResumeAllTheChannelsLoop
AlreadyResumed:						
	ret
DoorsAreOpen:
	mov	CsHeldFlag,2
	ret
	ProcEnd noret

	ProcBegin@ TmpltOpen,far
;	========================

;	Open the channel
;	DS,ES,SS Applications data space
;	Handle in DX

	cld
        pushf
        cli
        call    FindFreeChannel
        jnc     GotFreeChannel
        popf
LockedError:
	mov	ax,LockedErr
	stc
	ret
AllErrorsExitHere:
        push    ax
	HeapFreeCell
        pop     ax
FreeTckAndChannel:
        push    ax
        call    FreeHardware
        pop     ax
FreeTckAndExit:
        push    ax
        mov	bx,cs:[di].TmpltTckHandle
	IoClose
        pop     ax
CloseThenFree:
	mov	cs:[di].TmpltEntOpen,0
	stc
	ret
GotFreeChannel:
	mov	cs:[di].TmpltEntOpen,1
        mov     cs:[di].TmpltChannelStarted,0
        mov     cs:[di].TmpltChannelRunning,0
	popf
	xor	ax,ax
	push	ax
	mov	ax,((':' shl 8)+'K')
	push	ax
	mov	ax,(('C' shl 8)+'T')
	push	ax
	mov	bx,sp
	IoOpen
	jnc	GotATickChannel
	add	sp,6
	mov	ax,LockedErr
	jmp	CloseThenFree
GotATickChannel:
	add	sp,6
	mov	cs:[di].TmpltTckHandle,ax
	push	dx
	mov	bx,ax
	mov	ax,IoFuncStart
	mov	cx,1
	push	cx                                      ; Frequency 1 tick
	push	di                                      ; Data is our CS CB
	push	dx                                      ; Our device handle
	mov	cx,(MonitorVector-TableStart)/2         ; Vector to call
	push	cx
	mov	cx,sp
	IoWithWait
	add	sp,8
	pop	dx
        call    GetHardware
	jc 	FreeTckAndExit

	mov	cx,(size TmpltStruct)			; Get ourselfs a CB
	HeapAllocateCell				; In the applications
	jc	FreeTckAndChannel			; Data space

	mov	bx,ax
     	mov	[bx].Tmpltblk.ChanNext,bx
	mov	[bx].Tmpltblk.ChanSignature,IoChanSignature
	mov	[bx].Tmpltblk.ChanLibHandle,dx
	mov	[bx].TmpltEntPtr,di
        push    bx
        mov     bx,dx
	mov	cx,di
	IoRequestReset
        pop     bx
if      StartChannelInOpen
        call    StartChannelFromOpen
endif
	xor     ax,ax
	ret
	ProcEnd noret

StrategyVectorTable label word
        dw      offset StrategyDefault
        dw      offset StrategyDefault
        dw      offset StrategyDefault
        dw      offset TmpltClose
        dw      offset StrategyDefault
        dw      offset StrategyDefault
        dw      offset StrategyDefault
        dw      offset StrategyDefault
        dw      offset StrategyDefault
        dw      offset StrategyDefault
        dw      offset StrategyDefault
        dw      offset StrategyDefault
        dw      offset StrategyDefault
        dw      offset StrategyDefault

	ProcBegin@ TmpltStrategy,far
;	============================

;	BX is our control block
;	SI points to the parameters
;	DS,ES Applications data space

	mov	ax,[si].RqFunction
	mov	dx,[si].RqA1Ptr
	cmp	ax,IoFuncSuperFrame
	ja	StrategyDefault
	shl	ax,1
	mov	di,ax
	push	StrategyVectorTable[di]
	mov	di,[bx].TmpltEntPtr
        retn
StrategyDefault:
	IoRoot
	ret
ExitStrategyOkay:
        xor     ax,ax
ExitStrategy:
	mov	di,[si].RqStatusPtr
	mov	word ptr [di],ax
        cmp     ax,PendingErr
        je      JustExit
	IoSignal
JustExit:
	xor	ax,ax
	ret
	ProcEnd noret

	ProcBegin@ TmpltClose,far
;	=========================

;	Close a channel
;	DI CS control block
;       BX DS control block
;       SI points to aurguments on stack
;	DX Argument one pointer

        mov     ah,DevHoldPowerDown
	call	StopTheChannel
        call    FreeHardware
        mov     cs:[di].TmpltChannelStarted,0
        push    bx
	mov	bx,[bx].Tmpltblk.ChanLibHandle
	mov     cx,di
        IoRequestResetCancel
        pop     bx
	HeapFreeCell
        mov	bx,cs:[di].TmpltTckHandle
	IoClose
	mov	cs:[di].TmpltEntOpen,0
        jmp     short ExitStrategyOkay
	ProcEnd noret

	ProcBegin@ StartTheChannel
;	==========================

;       Start the Channel Running
;       Assume channel set up and interrupts off
	
        cmp     cs:[di].TmpltChannelRunning,0
        jne     ChannelAlreadyRunning

if      Asic5Type and NeedClocking
if      Asic9
	in	ax, A9WControlExtraRW                   ; Start the S3s clock
	or	ah, [bx].TmpltA5Clocking                ; Generator
	out	A9WControlExtraRW, ax
else
	mov	al, [bx].TmpltA5Clocking
        HwSetA2Control2Bits
endif
endif
if      NeedTheInterrupt
        mov     al, cs:[di].TmpltInterruptNumber        ; Load the address of
        mov     cx, cs                                  ; the appropriate
        mov     bx, cs:[di].TmpltInterruptVector        ; interrupt routine
        GenSetRevector                                  ; into the correct vector
if      Asic9
        in      al,A9BInterruptMaskRW			; Set the mask
        or      al,cs:[di].TmpltInterruptMask   	; to enable Interrupts
        out     A9BInterruptMaskRW,al
else
        in      al, A1InterruptMask
        or 	al,cs:[di].TmpltInterruptMask
        out     A1InterruptMask, al
endif
endif
        mov     cs:[di].TmpltChannelRunning,1
ChannelAlreadyRunning:
        ret
        ProcEnd noret

	ProcBegin@ StopTheChannel
;	=========================

;       Stop the Channel Running
;       Assume channel set up and interrupts off
;       Stop reason in AH

        cmp     byte ptr cs:[di].TmpltChannelRunning,0
        je      ChannelAlreadyStopped
if      NeedTheInterrupt
        mov     ah,cs:[di].TmpltInterruptMask			
        not     ah					
if      Asic9
        in      al,A9BInterruptMaskRW			; Stop Interrupts
        and     al,ah					; By clearing the  
        out     A9BInterruptMaskRW,al                   ; Mask and resetting
else                                                    ; The Vector
        in      al, A1InterruptMask
        and     al,ah
        out     A1InterruptMask, al
endif
        mov     al, cs:[di].TmpltInterruptNumber
        GenResetRevector
endif
if      Asic5Type and NeedClocking
if      Asic9
        mov     cl, [bx].TmpltA5Clocking                ; Turn off baud rate
        not     cl                                      ; clocking from the
        in      ax, A9WControlExtraRW                   ; S3/3a
        and     ah, cl
        out     A9WControlExtraRW, ax
else
	mov     al, [bx].TmpltA5Clocking                 
        HwClearA2Control2Bits
endif
endif
        mov     cs:[di].TmpltChannelRunning,0
ChannelAlreadyStopped:
        ret
        ProcEnd noret

if      StartChannelInOpen
	ProcBegin@ StartChannelFromOpen
;	===============================

        pushf
        cli
        mov     cs:[di].TmpltChannelStarted,1
        mov     al,cs:[di].TmpltChannel
        HwSelectChannel
        push    ax
        call    StartTheChannel
        pop     ax
        HwSelectChannel
        popf
        ret
        ProcEnd noret
endif
	ProcBegin@ GetHardware
;	======================

        mov     al, cs:[di].TmpltInterruptMask
	HwGetChannel
        jc      ChannelNotAvailable
        pushf
        cli
        mov     al,cs:[di].TmpltChannel
        HwSelectChannel
        push    ax
        call    CheckForHardware
        pop     ax
        jc      NoHardwareFreeTheChannel
        HwSelectChannel
        popf
        clc
        ret
NoHardwareFreeTheChannel:
        HwSelectChannel
        popf
        mov     al, cs:[di].TmpltInterruptMask
	HwFreeChannel
ChannelNotAvailable:
        stc
        ret
        ProcEnd noret

	ProcBegin@ FreeHardware
;	=======================

        mov     al, cs:[di].TmpltInterruptMask
	HwFreeChannel
        ret
        ProcEnd noret

	ProcBegin@ FindFreeChannel
;	==========================

	mov	si,[si].OpenNamePtr
	mov	al,[si+1]
        CharToFoldedChar
	cmp	al,'A'
	jb	CantGetThatChannel
	sub	al,'A'
	cmp	al,NumberOfChannels
	jae	CantGetThatChannel
        xor     ah,ah
        push    dx
        mov     dx,size TmpltEnt
        mul     dx
        pop     dx
        mov     di,ax
        add     di,offset Channel0
        cmp     cs:[di].TmpltEntOpen,0
        je      FoundAFreeChannel
CantGetThatChannel:
        stc
        ret
FoundAFreeChannel:
        clc
        ret
        ProcEnd noret

        ProcBegin@ CheckForHardware
;       ===========================

;       Assume Interrupts are off
;       Correct channel should be selected
;       Out: clc - got correct hardware
;            stc - wrong or no hardware

if      Asic5Type
	HwNullFrame					; Check that the    
	mov	al,(SerialSelect or Asic5NormalId)	; Harware is there
	SBUSY						; And that it is what
	SCONTOUT					; It should be
	XNOP						; First look for An
	SBUSY                                           ; ASIC5 at the other
	SDATAIN                                         ; End of the link
	test	al,al
	je	ConnectionFailed
GotConnection:
	popf
	clc
	ret
ConnectionFailed:
	mov	al, SerialSelect or Asic4Id             ; Asic4 Id
	SBUSY
	SCONTOUT
	XNOP
	SBUSY
	SDATAIN
        test    al, al
	jne	ConnectionFailedExit
else
	HwNullFrame
	mov	al,(SerialSelect or Asic4Id)
	SBUSY						; First look for An
	SCONTOUT					; ASIC4 at the other
	XNOP						; End of the link
	SBUSY
	SDATAIN
	test	al, al
	je	ConnectionFailed
	mov	al,SerialReadSingle or A4InfoR		; Now see if we have
	SBUSY						; The right card
	SCONTOUT	    				
	XNOP	; Allows the busy signal to come through for the wait
	SBUSY
	SDATAIN
	and	al,A4PERIPH_MASK
        cmp     al,TheInfoByteThatWeWant
        jne     ConnectionFailedExit
	clc
	ret
ConnectionFailed:
	mov	al,(SerialSelect or Asic5NormalId)	; Select as an
	SBUSY						; Asic5 peripheral
	SCONTOUT
	XNOP
	SDATAIN
	test	al,al
        jne     ConnectionFailedExit
endif
	mov	al, SerialSelect or Asic8Id             ; Modem chip Id
	SBUSY
	SCONTOUT
	XNOP
	SBUSY
	SDATAIN
        test    al, al
	jne	ConnectionFailedExit
	mov	al, SerialSelect or Asic5PackId         ; Asic5pack Id
	SBUSY
	SCONTOUT
	XNOP
	SBUSY
	SDATAIN
ConnectionFailedExit:
	stc
	ret
        ProcEnd noret

	ProcBegin@ MonitorInt,far
;	=========================

;       Called on every tick
;       Issues pack door hold and resumes
;       In:  Door state in SI

	cmp	si,DoorOpen
        je      TheDoorIsOpenSoCantDoAnything
	cmp	CsHeldFlag,2
        je      NeedToDoTheResume
        ret
NeedToDoTheResume:
	mov	CsHeldFlag,0
        jmp     DoResume
TheDoorIsOpenSoCantDoAnything:
	cmp	CsHeldFlag,0
        jne     DontNeedToHold
	mov	CsHeldFlag,2
        mov     ah,DevHoldPowerFail
        jmp     DoHold
DontNeedToHold:
        ret
        ProcEnd noret

if      NeedTheInterrupt
  ife     Consumer
        ProcBegin@ Interrupt2,far
;       =========================

        mov     di,offset Channel2
        mov     ax,PortCActive
        jmp     ComInt
        ProcEnd noret

        ProcBegin@ Interrupt1,far
;       =========================

        mov     di,offset Channel1
        mov     ax,PortBActive
        jmp     ComInt
        ProcEnd noret
  endif

        ProcBegin@ Interrupt0,far
;       =========================

        mov     di,offset Channel0
        mov     ax,PortAActive
;       FALLTHROUGH to ComInt
        ProcEnd noret

        ProcBegin@ ComInt,far
;       =====================

if      Asic9
        out     A9BNonSpecificEoiW,al			
else
        out     A1NonSpecificEoi, al
endif
        clc
        ret
        ProcEnd noret
endif


	EndCodeSeg
	stack segment stack para 'data'
	stack ends
	end TmpltLDD












